package cn.fuxi2022.module.pay.service;

import cn.fuxi2022.model.empty.applets.GroupStudentPayLog;

import javax.servlet.http.HttpServletRequest;
import java.time.format.DateTimeFormatter;
import java.util.Map;

public interface WeChatPayService {

    /**
     * 创建订单时的签名类型
     */
    String SIGN_TYPE = "MD5";

    /**
     * 微信支付订单完成时间的格式化
     */
    DateTimeFormatter TIME_END_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");


    /**
     * 获取当前用户的订单，根据订单获取小程序支付所需参数
     * <p>
     * 如果当前用户不存在订单，创建支付订单
     * 如果当前用户的订单失败超时，就重新创建支付订单
     *
     * @param openId 当前用户的openId
     * @param id     当前用户的id
     * @return 返回微信小程序下单所需参数 + 价格（如果价格为0，说明当前用户已经支付）
     */
    Map getOrder(String openId, String id);


    /**
     * JSAPI下单：调用该接口在微信支付服务后台生成预支付交易单
     * 当前用户没有订单时，或因为订单已经关闭需要重新创建订单时，调用该方法
     *
     * @param openId 当前用户的openId
     * @param id     当前用户的id
     * @return 返回微信小程序下单所需参数
     */
    Map createOrder(String openId, String id);

    /**
     * 获取社团订单对象（最后一个订单）
     * 如果当前订单为未支付，将请求微信服务器再次查询
     * 保证订单在当时是最新的
     * 对未支付或失败订单进行操作前，需要再次检查更新
     * 防止在查询后，用户进行了支付。
     *
     * @param id 当前用户的Id
     * @return 当前用户没有订单就是NULL，否则返回当前用户的最后一个订单对象
     */
    GroupStudentPayLog selectOrder(String id);

    /**
     * 请求微信服务器，更新订单的方法
     * 该方法用于当前订单处于未支付状态，需要请求微信服务器，判断订单是否支付成功
     *
     * @param orderNo 订单流水号
     */
    void checkOrder(String orderNo);

    /**
     * 支付通知API：微信支付通过支付通知接口将用户支付成功消息通知给商户
     * 支付成功后，微信服务器回调该接口，传递订单数据
     *
     * <p>
     * 注意：
     * A.同样的通知可能会多次发送给系统。系统必须能够正确处理重复的通知
     * B.商户系统对于开启结果通知的内容一定要做签名验证，并校验通知的信息是否与商户侧的信息一致，防止数据泄露导致出现“假通知”，造成资金损失
     * <p>
     * 根据以上情况，我们做出决定，不认可回调过来的数据，而是系统手动请求微信服务器，防止假通知
     *
     * @param request 微信服务器的回调（不信任）
     * @return 成功回调
     */
    String payCallback(HttpServletRequest request);


    /**
     * 请求微信服务器，关闭订单的方法（MQ使用）
     * 该方法用于当前订单处于未支付状态，并且已经超时，需要请求微信服务器，关闭订单，防止重复支付
     *
     * @param orderNo 订单流水号
     */
    void closeOrder(String orderNo);

    /**
     * 提醒用户完成订单支付（MQ使用）
     * 该方法用于发送公众号消息，提醒用户进行支付
     * 如果 当前订单超时时间 已经过去，就不再提醒
     * 如果  当前时间加上订单超时时间后，订单已经超时，就不再提醒
     *
     * @param orderNo 订单流水号
     */
    void sendOrderMsg(String orderNo);

    /**
     * 对成功的订单退款（危险！！！）
     *
     * @param orderNo 订单流水号
     */
    void refundOrder(String orderNo);
}
